home *** CD-ROM | disk | FTP | other *** search
/ Inter.Net 55-1 / Inter.Net 55-1.iso / CBuilder / Setup / BCB / data.z / statreg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-02-09  |  22.9 KB  |  1,035 lines

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10.  
  11. ///////////////////////////////////////
  12. #define RET_ON_ERROR(x) \
  13.         if (FAILED(hr = x))\
  14.             return hr;
  15. ///////////////////////////////////////
  16. #define BREAK_ON_ERROR(x) \
  17.         if (FAILED(hr = x))\
  18.             break;
  19. ///////////////////////////////////////
  20. #ifdef _DEBUG
  21. #define REPORT_ERROR(name, func) \
  22.         if (func != ERROR_SUCCESS)\
  23.             ATLTRACE(_T("NON CRITICAL ERROR : %s failed\n"), name);
  24. #define REG_TRACE_RECOVER() \
  25.         if (!bRecover) \
  26.             ATLTRACE(_T("Opened Key %s\n"), szToken); \
  27.         else \
  28.             ATLTRACE(_T("Ignoring Open key on %s : In Recovery mode\n"), szToken);
  29. #else //!_DEBUG
  30. #define REG_TRACE_RECOVER()
  31. #define REPORT_ERROR(name, func) \
  32.         func;
  33. #endif //_DEBUG
  34.  
  35. ///////////////////////////////////////
  36. #define MAX_TYPE            MAX_VALUE
  37. #define MAX_VALUE           4096
  38.  
  39. #ifndef ATL_NO_NAMESPACE
  40. namespace ATL
  41. {
  42. #endif
  43.  
  44. class CParseBuffer
  45. {
  46. public:
  47.     int nPos;
  48.     int nSize;
  49.     LPTSTR p;
  50.     CParseBuffer(int nInitial);
  51.     ~CParseBuffer() {CoTaskMemFree(p);}
  52.     BOOL AddChar(TCHAR ch);
  53.     BOOL AddString(LPCOLESTR lpsz);
  54.     LPTSTR Detach();
  55.  
  56. };
  57.  
  58. LPCTSTR   rgszNeverDelete[] = //Component Catagories
  59. {
  60.     _T("CLSID"), _T("TYPELIB")
  61. };
  62.  
  63. const int   cbNeverDelete = sizeof(rgszNeverDelete) / sizeof(LPCTSTR*);
  64.  
  65. static LPTSTR StrChr(LPTSTR lpsz, TCHAR ch)
  66. {
  67.     LPTSTR p = NULL;
  68.     while (*lpsz)
  69.     {
  70.         if (*lpsz == ch)
  71.         {
  72.             p = lpsz;
  73.             break;
  74.         }
  75.         lpsz = CharNext(lpsz);
  76.     }
  77.     return p;
  78. }
  79.  
  80. static HKEY WINAPI HKeyFromString(LPTSTR szToken)
  81. {
  82.     struct keymap
  83.     {
  84.         LPCTSTR lpsz;
  85.         HKEY hkey;
  86.     };
  87.     static const keymap map[] = {
  88.         {_T("HKCR"), HKEY_CLASSES_ROOT},
  89.         {_T("HKCU"), HKEY_CURRENT_USER},
  90.         {_T("HKLM"), HKEY_LOCAL_MACHINE},
  91.         {_T("HKU"),  HKEY_USERS},
  92.         {_T("HKPD"), HKEY_PERFORMANCE_DATA},
  93.         {_T("HKDD"), HKEY_DYN_DATA},
  94.         {_T("HKCC"), HKEY_CURRENT_CONFIG},
  95.         {_T("HKEY_CLASSES_ROOT"), HKEY_CLASSES_ROOT},
  96.         {_T("HKEY_CURRENT_USER"), HKEY_CURRENT_USER},
  97.         {_T("HKEY_LOCAL_MACHINE"), HKEY_LOCAL_MACHINE},
  98.         {_T("HKEY_USERS"), HKEY_USERS},
  99.         {_T("HKEY_PERFORMANCE_DATA"), HKEY_PERFORMANCE_DATA},
  100.         {_T("HKEY_DYN_DATA"), HKEY_DYN_DATA},
  101.         {_T("HKEY_CURRENT_CONFIG"), HKEY_CURRENT_CONFIG}
  102.     };
  103.  
  104.     for (int i=0;i<sizeof(map)/sizeof(keymap);i++)
  105.     {
  106.         if (!lstrcmpi(szToken, map[i].lpsz))
  107.             return map[i].hkey;
  108.     }
  109.     return NULL;
  110. }
  111.  
  112. static HKEY HKeyFromCompoundString(LPTSTR szToken, LPTSTR& szTail)
  113. {
  114.     if (NULL == szToken)
  115.         return NULL;
  116.  
  117.     LPTSTR lpsz = StrChr(szToken, chDirSep);
  118.  
  119.     if (NULL == lpsz)
  120.         return NULL;
  121.  
  122.     szTail = CharNext(lpsz);
  123.     *lpsz = chEOS;
  124.     HKEY hKey = HKeyFromString(szToken);
  125.     *lpsz = chDirSep;
  126.     return hKey;
  127. }
  128.  
  129. static LPVOID QueryValue(HKEY hKey, LPCTSTR szValName, DWORD& dwType)
  130. {
  131.     DWORD dwCount = 0;
  132.  
  133.     if (RegQueryValueEx(hKey, szValName, NULL, &dwType, NULL, &dwCount) != ERROR_SUCCESS)
  134.     {
  135.         ATLTRACE(_T("RegQueryValueEx failed for Value %s\n"), szValName);
  136.         return NULL;
  137.     }
  138.  
  139.     if (!dwCount)
  140.     {
  141.         ATLTRACE(_T("RegQueryValueEx returned 0 bytes\n"));
  142.         return NULL;
  143.     }
  144.  
  145.     // Not going to Check for fail on CoTaskMemAlloc & RegQueryValueEx as NULL
  146.     // will be returned regardless if anything failed
  147.  
  148.     LPVOID pData = CoTaskMemAlloc(dwCount);
  149.     RegQueryValueEx(hKey, szValName, NULL, &dwType, (LPBYTE) pData, &dwCount);
  150.     return pData;
  151. }
  152.  
  153. /////////////////////////////////////////////////////////////////////////////
  154. //
  155.  
  156. HRESULT CRegParser::GenerateError(UINT nID)
  157. {
  158. //  m_re.m_nID   = nID;
  159. //  m_re.m_cLines = m_cLines;
  160.     return DISP_E_EXCEPTION;
  161. }
  162.  
  163.  
  164. CRegParser::CRegParser(CRegObject* pRegObj)
  165. {
  166.     m_pRegObj           = pRegObj;
  167.     m_pchCur            = NULL;
  168.     m_cLines            = 1;
  169. }
  170.  
  171. BOOL CRegParser::IsSpace(TCHAR ch)
  172. {
  173.     switch (ch)
  174.     {
  175.         case chSpace:
  176.         case chTab:
  177.         case chCR:
  178.         case chLF:
  179.                 return TRUE;
  180.     }
  181.  
  182.     return FALSE;
  183. }
  184.  
  185. void CRegParser::IncrementLinePos()
  186. {
  187.     m_pchCur = CharNext(m_pchCur);
  188.     if (chLF == *m_pchCur)
  189.         IncrementLineCount();
  190. }
  191.  
  192. void CRegParser::SkipWhiteSpace()
  193. {
  194.     while(IsSpace(*m_pchCur))
  195.         IncrementLinePos();
  196. }
  197.  
  198. HRESULT CRegParser::NextToken(LPTSTR szToken)
  199. {
  200.     USES_CONVERSION;
  201.  
  202.     UINT ichToken = 0;
  203.  
  204.     SkipWhiteSpace();
  205.  
  206.     // NextToken cannot be called at EOS
  207.     if (chEOS == *m_pchCur)
  208.         return GenerateError(E_ATL_UNEXPECTED_EOS);
  209.  
  210.     // handle quoted value / key
  211.     if (chQuote == *m_pchCur)
  212.     {
  213.         LPCTSTR szOrig = szToken;
  214.  
  215.         IncrementLinePos(); // Skip Quote
  216.  
  217.         while (chEOS != *m_pchCur && !EndOfVar())
  218.         {
  219.             if (chQuote == *m_pchCur) // If it is a quote that means we must skip it
  220.                 IncrementLinePos();   // as it has been escaped
  221.  
  222.             LPTSTR pchPrev = m_pchCur;
  223.             IncrementLinePos();
  224.  
  225.             if (szToken + sizeof(WORD) >= MAX_VALUE + szOrig)
  226.                 return GenerateError(E_ATL_VALUE_TOO_LARGE);
  227.             for (int i = 0; pchPrev+i < m_pchCur; i++, szToken++)
  228.                 *szToken = *(pchPrev+i);
  229.         }
  230.  
  231.         if (chEOS == *m_pchCur)
  232.         {
  233.             ATLTRACE(_T("NextToken : Unexpected End of File\n"));
  234.             return GenerateError(E_ATL_UNEXPECTED_EOS);
  235.         }
  236.  
  237.         *szToken = chEOS;
  238.         IncrementLinePos(); // Skip end quote
  239.     }
  240.  
  241.     else
  242.     {   // Handle non-quoted ie parse up till first "White Space"
  243.         while (chEOS != *m_pchCur && !IsSpace(*m_pchCur))
  244.         {
  245.             LPTSTR pchPrev = m_pchCur;
  246.             IncrementLinePos();
  247.             for (int i = 0; pchPrev+i < m_pchCur; i++, szToken++)
  248.                 *szToken = *(pchPrev+i);
  249.         }
  250.  
  251.         *szToken = chEOS;
  252.     }
  253.     return S_OK;
  254. }
  255.  
  256. static BOOL VTFromRegType(LPCTSTR szValueType, VARTYPE& vt)
  257. {
  258.     struct typemap
  259.     {
  260.         LPCTSTR lpsz;
  261.         VARTYPE vt;
  262.     };
  263.     static const typemap map[] = {
  264.         {szStringVal, VT_BSTR},
  265.         {szDwordVal,  VT_I4}
  266.     };
  267.  
  268.     for (int i=0;i<sizeof(map)/sizeof(typemap);i++)
  269.     {
  270.         if (!lstrcmpi(szValueType, map[i].lpsz))
  271.         {
  272.             vt = map[i].vt;
  273.             return TRUE;
  274.         }
  275.     }
  276.  
  277.     return FALSE;
  278.  
  279. }
  280.  
  281. HRESULT CRegParser::AddValue(CRegKey& rkParent,LPCTSTR szValueName, LPTSTR szToken)
  282. {
  283.     USES_CONVERSION;
  284.     HRESULT hr;
  285.  
  286.     TCHAR       szTypeToken[MAX_TYPE];
  287.     VARTYPE     vt;
  288.     LONG        lRes = ERROR_SUCCESS;
  289.     UINT        nIDRes = 0;
  290.  
  291.     RET_ON_ERROR(NextToken(szTypeToken))
  292.     if (!VTFromRegType(szTypeToken, vt))
  293.     {
  294.         ATLTRACE(_T("%s Type not supported\n"), szTypeToken);
  295.         return GenerateError(E_ATL_TYPE_NOT_SUPPORTED);
  296.     }
  297.  
  298.     TCHAR szValue[MAX_VALUE];
  299.     SkipWhiteSpace();
  300.     RET_ON_ERROR(NextToken(szValue));
  301.     long lVal;
  302.  
  303.     switch (vt)
  304.     {
  305.     case VT_BSTR:
  306.         lRes = rkParent.SetValue(szValue, szValueName);
  307.         ATLTRACE(_T("Setting Value %s at %s\n"), szValue, !szValueName ? _T("default") : szValueName);
  308.         break;
  309.     case VT_I4:
  310.         VarI4FromStr(T2OLE(szValue), 0, 0, &lVal);
  311.         lRes = rkParent.SetValue(lVal, szValueName);
  312.         ATLTRACE(_T("Setting Value %d at %s\n"), lVal, !szValueName ? _T("default") : szValueName);
  313.         break;
  314.     }
  315.  
  316.     if (ERROR_SUCCESS != lRes)
  317.     {
  318.         nIDRes = E_ATL_VALUE_SET_FAILED;
  319.         hr = HRESULT_FROM_WIN32(lRes);
  320.     }
  321.  
  322.     RET_ON_ERROR(NextToken(szToken))
  323.  
  324.     return S_OK;
  325. }
  326.  
  327. BOOL CRegParser::CanForceRemoveKey(LPCTSTR szKey)
  328. {
  329.     for (int iNoDel = 0; iNoDel < cbNeverDelete; iNoDel++)
  330.         if (!lstrcmpi(szKey, rgszNeverDelete[iNoDel]))
  331.              return FALSE;                       // We cannot delete it
  332.  
  333.     return TRUE;
  334. }
  335.  
  336. BOOL CRegParser::HasSubKeys(HKEY hkey)
  337. {
  338.     DWORD       cbSubKeys = 0;
  339.  
  340.     if (FAILED(RegQueryInfoKey(hkey, NULL, NULL, NULL,
  341.                                &cbSubKeys, NULL, NULL,
  342.                                NULL, NULL, NULL, NULL, NULL)))
  343.     {
  344.         ATLTRACE(_T("Should not be here!!\n"));
  345.         _ASSERTE(FALSE);
  346.         return FALSE;
  347.     }
  348.  
  349.     return cbSubKeys > 0;
  350. }
  351.  
  352. BOOL CRegParser::HasValues(HKEY hkey)
  353. {
  354.     DWORD       cbValues = 0;
  355.  
  356.     LONG lResult = RegQueryInfoKey(hkey, NULL, NULL, NULL,
  357.                                   NULL, NULL, NULL,
  358.                                   &cbValues, NULL, NULL, NULL, NULL);
  359.     if (ERROR_SUCCESS != lResult)
  360.     {
  361.         ATLTRACE(_T("RegQueryInfoKey Failed "));
  362.         _ASSERTE(FALSE);
  363.         return FALSE;
  364.     }
  365.  
  366.     if (1 == cbValues)
  367.     {
  368.         DWORD cbData = 0;
  369.         lResult = RegQueryValueEx(hkey, NULL, NULL, NULL, NULL, &cbData);
  370.  
  371.         if (ERROR_SUCCESS == lResult)
  372.             return !cbData;
  373.         else
  374.             return TRUE;
  375.     }
  376.  
  377.     return cbValues > 0;
  378. }
  379.  
  380. HRESULT CRegParser::SkipAssignment(LPTSTR szToken)
  381. {
  382.     HRESULT hr;
  383.     TCHAR szValue[MAX_VALUE];
  384.  
  385.     if (*szToken == chEquals)
  386.     {
  387.         RET_ON_ERROR(NextToken(szToken))
  388.         // Skip assignment
  389.         SkipWhiteSpace();
  390.         RET_ON_ERROR(NextToken(szValue));
  391.         RET_ON_ERROR(NextToken(szToken))
  392.     }
  393.  
  394.     return S_OK;
  395. }
  396.  
  397.  
  398. HRESULT CRegParser::RegisterSubkeys(HKEY hkParent, BOOL bRegister, BOOL bRecover)
  399. {
  400.     CRegKey keyCur;
  401.     TCHAR   szToken[MAX_VALUE];
  402.     LONG    lRes;
  403.     TCHAR   szKey[MAX_VALUE];
  404.     BOOL    bDelete = TRUE;
  405.     BOOL    bInRecovery = bRecover;
  406.     HRESULT hr = S_OK;
  407.  
  408.     ATLTRACE(_T("Num Els = %d\n"), cbNeverDelete);
  409.     RET_ON_ERROR(NextToken(szToken))  // Should be key name
  410.  
  411.  
  412.     while (*szToken != chRightBracket) // Continue till we see a }
  413.     {
  414.         BOOL bTokenDelete = !lstrcmpi(szToken, szDelete);
  415.  
  416.         if (!lstrcmpi(szToken, szForceRemove) || bTokenDelete)
  417.         {
  418.             BREAK_ON_ERROR(NextToken(szToken))
  419.  
  420.             if (bRegister)
  421.             {
  422.                 CRegKey rkForceRemove;
  423.  
  424.                 if (StrChr(szToken, chDirSep) != NULL)
  425.                     return GenerateError(E_ATL_COMPOUND_KEY);
  426.  
  427.                 if (CanForceRemoveKey(szToken))
  428.                 {
  429.                     rkForceRemove.Attach(hkParent);
  430.                     rkForceRemove.RecurseDeleteKey(szToken);
  431.                     rkForceRemove.Detach();
  432.                 }
  433.                 if (bTokenDelete)
  434.                 {
  435.                     BREAK_ON_ERROR(NextToken(szToken))
  436.                     BREAK_ON_ERROR(SkipAssignment(szToken))
  437.                     goto EndCheck;
  438.                 }
  439.             }
  440.  
  441.         }
  442.  
  443.         if (!lstrcmpi(szToken, szNoRemove))
  444.         {
  445.             bDelete = FALSE;    // set even for register
  446.             BREAK_ON_ERROR(NextToken(szToken))
  447.         }
  448.  
  449.         if (!lstrcmpi(szToken, szValToken)) // need to add a value to hkParent
  450.         {
  451.             TCHAR  szValueName[_MAX_PATH];
  452.  
  453.             BREAK_ON_ERROR(NextToken(szValueName))
  454.             BREAK_ON_ERROR(NextToken(szToken))
  455.  
  456.             if (*szToken != chEquals)
  457.                 return GenerateError(E_ATL_EXPECTING_EQUAL);
  458.  
  459.             if (bRegister)
  460.             {
  461.                 CRegKey rk;
  462.  
  463.                 rk.Attach(hkParent);
  464.                 hr = AddValue(rk, szValueName, szToken);
  465.                 rk.Detach();
  466.  
  467.                 if (FAILED(hr))
  468.                     return hr;
  469.  
  470.                 goto EndCheck;
  471.             }
  472.             else
  473.             {
  474.                 if (!bRecover)
  475.                 {
  476.                     ATLTRACE(_T("Deleting %s\n"), szValueName);
  477.                     REPORT_ERROR(_T("RegDeleteValue"), RegDeleteValue(hkParent, szValueName))
  478.                 }
  479.  
  480.                 BREAK_ON_ERROR(SkipAssignment(szToken)) // Strip off type
  481.                 continue;  // can never have a subkey
  482.             }
  483.         }
  484.  
  485.         if (StrChr(szToken, chDirSep) != NULL)
  486.             return GenerateError(E_ATL_COMPOUND_KEY);
  487.  
  488.         if (bRegister)
  489.         {
  490.             lRes = keyCur.Open(hkParent, szToken, KEY_ALL_ACCESS);
  491.             if (ERROR_SUCCESS != lRes)
  492.             {
  493.                 // Failed all access try read only
  494.                 lRes = keyCur.Open(hkParent, szToken, KEY_READ);
  495.                 if (ERROR_SUCCESS != lRes)
  496.                 {
  497.                     // Finally try creating it
  498.                     ATLTRACE(_T("Creating key %s\n"), szToken);
  499.                     lRes = keyCur.Create(hkParent, szToken);
  500.                     if (ERROR_SUCCESS != lRes)
  501.                         return GenerateError(E_ATL_CREATE_KEY_FAILED);
  502.                 }
  503.             }
  504.  
  505.             BREAK_ON_ERROR(NextToken(szToken))
  506.  
  507.             if (*szToken == chEquals)
  508.                 BREAK_ON_ERROR(AddValue(keyCur, NULL, szToken)) // NULL == default
  509.         }
  510.         else
  511.         {
  512.             if (!bRecover && keyCur.Open(hkParent, szToken) != ERROR_SUCCESS)
  513.                 bRecover = TRUE;
  514.  
  515.             // TRACE out Key open status and if in recovery mode
  516.             REG_TRACE_RECOVER()
  517.  
  518.             // Remember Subkey
  519.             lstrcpyn(szKey, szToken, _MAX_PATH);
  520.  
  521.             // If in recovery mode
  522.  
  523.             if (bRecover || HasSubKeys(keyCur) || HasValues(keyCur))
  524.             {
  525.                 BREAK_ON_ERROR(NextToken(szToken))
  526.                 BREAK_ON_ERROR(SkipAssignment(szToken))
  527.  
  528.                 if (*szToken == chLeftBracket)
  529.                 {
  530.                     BREAK_ON_ERROR(RegisterSubkeys(keyCur.m_hKey, bRegister, bRecover))
  531.                     if (bRecover) // Turn off recovery if we are done
  532.                     {
  533.                         bRecover = bInRecovery;
  534.                         ATLTRACE(_T("Ending Recovery Mode\n"));
  535.                         BREAK_ON_ERROR(NextToken(szToken))
  536.                         BREAK_ON_ERROR(SkipAssignment(szToken))
  537.                         continue;
  538.                     }
  539.                 }
  540.  
  541.                 if (!bRecover && HasSubKeys(keyCur))
  542.                 {
  543.                     // See if the KEY is in the NeverDelete list and if so, don't
  544.                     if (CanForceRemoveKey(szKey))
  545.                     {
  546.                         ATLTRACE(_T("Deleting non-empty subkey %s by force\n"), szKey);
  547.                         REPORT_ERROR(_T("RecurseDeleteKey"), keyCur.RecurseDeleteKey(szKey))
  548.                     }
  549.                     BREAK_ON_ERROR(NextToken(szToken))
  550.                     continue;
  551.                 }
  552.  
  553.                 if (bRecover)
  554.                     continue;
  555.             }
  556.  
  557.             if (!bRecover && keyCur.Close() != ERROR_SUCCESS)
  558.                return GenerateError(E_ATL_CLOSE_KEY_FAILED);
  559.  
  560.             if (!bRecover && bDelete)
  561.             {
  562.                 ATLTRACE(_T("Deleting Key %s\n"), szKey);
  563.                 REPORT_ERROR(_T("RegDeleteKey"), RegDeleteKey(hkParent, szKey))
  564.             }
  565.  
  566.             BREAK_ON_ERROR(NextToken(szToken))
  567.             BREAK_ON_ERROR(SkipAssignment(szToken))
  568.         }
  569.  
  570. EndCheck:
  571.  
  572.         if (bRegister)
  573.         {
  574.             if (*szToken == chLeftBracket)
  575.             {
  576.                 BREAK_ON_ERROR(RegisterSubkeys(keyCur.m_hKey, bRegister, FALSE))
  577.                 BREAK_ON_ERROR(NextToken(szToken))
  578.             }
  579.         }
  580.     }
  581.  
  582.     return hr;
  583. }
  584.  
  585. LPTSTR CParseBuffer::Detach()
  586. {
  587.     LPTSTR lp = p;
  588.     p = NULL;
  589.     return lp;
  590. }
  591.  
  592. CParseBuffer::CParseBuffer(int nInitial)
  593. {
  594.     nPos = 0;
  595.     nSize = nInitial;
  596.     p = (LPTSTR) CoTaskMemAlloc(nSize*sizeof(TCHAR));
  597. }
  598.  
  599. BOOL CParseBuffer::AddString(LPCOLESTR lpsz)
  600. {
  601.     USES_CONVERSION;
  602.     LPCTSTR lpszT = OLE2CT(lpsz);
  603.     while (*lpszT)
  604.     {
  605.         AddChar(*lpszT);
  606.         lpszT++;
  607.     }
  608.     return TRUE;
  609. }
  610.  
  611. BOOL CParseBuffer::AddChar(TCHAR ch)
  612. {
  613.     if (nPos == nSize) // realloc
  614.     {
  615.         nSize *= 2;
  616.         p = (LPTSTR) CoTaskMemRealloc(p, nSize*sizeof(TCHAR));
  617.     }
  618.     p[nPos++] = ch;
  619.     return TRUE;
  620. }
  621.  
  622. HRESULT CRegParser::PreProcessBuffer(LPTSTR lpszReg, LPTSTR* ppszReg)
  623. {
  624.     USES_CONVERSION;
  625.     _ASSERTE(lpszReg != NULL);
  626.     _ASSERTE(ppszReg != NULL);
  627.     *ppszReg = NULL;
  628.     int nSize = lstrlen(lpszReg)*2;
  629.     CParseBuffer pb(nSize);
  630.     if (pb.p == NULL)
  631.         return E_OUTOFMEMORY;
  632.     m_pchCur = lpszReg;
  633.     HRESULT hr = S_OK;
  634.  
  635.     while (*m_pchCur != NULL) // look for end
  636.     {
  637.         if (*m_pchCur == _T('%'))
  638.         {
  639.             IncrementLinePos();
  640.             if (*m_pchCur == _T('%'))
  641.                 pb.AddChar(*m_pchCur);
  642.             else
  643.             {
  644.                 LPTSTR lpszNext = StrChr(m_pchCur, _T('%'));
  645.                 if (lpszNext == NULL)
  646.                 {
  647.                     ATLTRACE(_T("Error no closing % found\n"));
  648.                     hr = GenerateError(E_ATL_UNEXPECTED_EOS);
  649.                     break;
  650.                 }
  651.                 int nLength = lpszNext - m_pchCur;
  652.                 if (nLength > 31)
  653.                 {
  654.                     hr = E_FAIL;
  655.                     break;
  656.                 }
  657.                 TCHAR buf[32];
  658.                 lstrcpyn(buf, m_pchCur, nLength+1);
  659.                 LPCOLESTR lpszVar = m_pRegObj->StrFromMap(buf);
  660.                 if (lpszVar == NULL)
  661.                 {
  662.                     hr = GenerateError(E_ATL_NOT_IN_MAP);
  663.                     break;
  664.                 }
  665.                 pb.AddString(lpszVar);
  666.                 while (m_pchCur != lpszNext)
  667.                     IncrementLinePos();
  668.             }
  669.         }
  670.         else
  671.             pb.AddChar(*m_pchCur);
  672.         IncrementLinePos();
  673.     }
  674.     pb.AddChar(NULL);
  675.     if (SUCCEEDED(hr))
  676.         *ppszReg = pb.Detach();
  677.     return hr;
  678. }
  679.  
  680. HRESULT CRegParser::RegisterBuffer(LPTSTR szBuffer, BOOL bRegister)
  681. {
  682.     TCHAR   szToken[_MAX_PATH];
  683.     HRESULT hr = S_OK;
  684.  
  685.     LPTSTR szReg;
  686.     hr = PreProcessBuffer(szBuffer, &szReg);
  687.     if (FAILED(hr))
  688.         return hr;
  689.  
  690.     m_pchCur = szReg;
  691.  
  692.     // Preprocess szReg
  693.  
  694.     while (chEOS != *m_pchCur)
  695.     {
  696.         BREAK_ON_ERROR(NextToken(szToken))
  697.         HKEY hkBase;
  698.         if ((hkBase = HKeyFromString(szToken)) == NULL)
  699.         {
  700.             ATLTRACE(_T("HKeyFromString failed on %s\n"), szToken);
  701.             hr = GenerateError(E_ATL_BAD_HKEY);
  702.             break;
  703.         }
  704.  
  705.         BREAK_ON_ERROR(NextToken(szToken))
  706.  
  707.         if (chLeftBracket != *szToken)
  708.         {
  709.             ATLTRACE(_T("Syntax error, expecting a {, found a %s\n"), szToken);
  710.             hr = GenerateError(E_ATL_MISSING_OPENKEY_TOKEN);
  711.             break;
  712.         }
  713.         if (bRegister)
  714.         {
  715.             LPTSTR szRegAtRegister = m_pchCur;
  716.             hr = RegisterSubkeys(hkBase, bRegister);
  717.             if (FAILED(hr))
  718.             {
  719.                 ATLTRACE(_T("Failed to register, cleaning up!\n"));
  720.                 m_pchCur = szRegAtRegister;
  721.                 RegisterSubkeys(hkBase, FALSE);
  722.                 break;
  723.             }
  724.         }
  725.         else
  726.         {
  727.             BREAK_ON_ERROR(RegisterSubkeys(hkBase, bRegister))
  728.         }
  729.  
  730.         SkipWhiteSpace();
  731.     }
  732.     CoTaskMemFree(szReg);
  733.     return hr;
  734. }
  735.  
  736. HRESULT CExpansionVector::Add(LPCOLESTR lpszKey, LPCOLESTR lpszValue)
  737. {
  738.     USES_CONVERSION;
  739.     HRESULT hr = S_OK;
  740.  
  741.     EXPANDER* pExpand = NULL;
  742.     ATLTRY(pExpand = new EXPANDER);
  743.     if (pExpand == NULL)
  744.         return E_OUTOFMEMORY;
  745.  
  746.     DWORD cbKey = (ocslen(lpszKey)+1)*sizeof(OLECHAR);
  747.     DWORD cbValue = (ocslen(lpszValue)+1)*sizeof(OLECHAR);
  748.     pExpand->szKey = (LPOLESTR)CoTaskMemAlloc(cbKey);
  749.     pExpand->szValue = (LPOLESTR)CoTaskMemAlloc(cbValue);
  750.     if (pExpand->szKey == NULL || pExpand->szValue == NULL)
  751.     {
  752.         CoTaskMemFree(pExpand->szKey);
  753.         CoTaskMemFree(pExpand->szValue);
  754.         delete pExpand;
  755.         return E_OUTOFMEMORY;
  756.     }
  757.     memcpy(pExpand->szKey, lpszKey, cbKey);
  758.     memcpy(pExpand->szValue, lpszValue, cbValue);
  759.  
  760.     if (m_cEls == m_nSize)
  761.     {
  762.         m_nSize*=2;
  763.         m_p = (EXPANDER**)realloc(m_p, m_nSize*sizeof(EXPANDER*));
  764.     }
  765.  
  766.     if (NULL != m_p)
  767.     {
  768.         m_p[m_cEls] = pExpand;
  769.         m_cEls++;
  770.     }
  771.     else
  772.         hr = E_OUTOFMEMORY;
  773.  
  774.     return hr;
  775.  
  776. }
  777.  
  778. LPCOLESTR CExpansionVector::Find(LPTSTR lpszKey)
  779. {
  780.     USES_CONVERSION;
  781.     for (int iExpand = 0; iExpand < m_cEls; iExpand++)
  782.     {
  783.         if (!lstrcmpi(OLE2T(m_p[iExpand]->szKey), lpszKey)) //are equal
  784.             return m_p[iExpand]->szValue;
  785.     }
  786.     return NULL;
  787. }
  788.  
  789. HRESULT CExpansionVector::ClearReplacements()
  790. {
  791.     for (int iExpand = 0; iExpand < m_cEls; iExpand++)
  792.     {
  793.         EXPANDER* pExp = m_p[iExpand];
  794.         CoTaskMemFree(pExp->szValue);
  795.         CoTaskMemFree(pExp->szKey);
  796.         delete pExp;
  797.     }
  798.     m_cEls = 0;
  799.     return S_OK;
  800. }
  801.  
  802. HRESULT CRegObject::GenerateError(UINT nID)
  803. {
  804. //  re.m_nID    = nID;
  805. //  re.m_cLines = -1;
  806.  
  807.     return DISP_E_EXCEPTION;
  808. }
  809.  
  810. HRESULT STDMETHODCALLTYPE CRegObject::AddReplacement(LPCOLESTR lpszKey, LPCOLESTR lpszItem)
  811. {
  812.     m_csMap.Lock();
  813.     HRESULT hr = m_RepMap.Add(lpszKey, lpszItem);
  814.     m_csMap.Unlock();
  815.     return hr;
  816. }
  817.  
  818. HRESULT CRegObject::RegisterFromResource(LPCOLESTR bstrFileName, LPCTSTR szID,
  819.                                          LPCTSTR szType, BOOL bRegister)
  820. {
  821.     USES_CONVERSION;
  822.  
  823.     HRESULT     hr;
  824.     CRegParser  parser(this);
  825.     HINSTANCE   hInstResDll;
  826.     HRSRC       hrscReg;
  827.     HGLOBAL     hReg;
  828.     DWORD       dwSize;
  829.     LPSTR       szRegA;
  830.     LPTSTR      szReg;
  831.  
  832.     hInstResDll = LoadLibraryEx(OLE2CT(bstrFileName), NULL, LOAD_LIBRARY_AS_DATAFILE);
  833.  
  834.     if (NULL == hInstResDll)
  835.     {
  836.         ATLTRACE(_T("Failed to LoadLibrary on %s\n"), OLE2CT(bstrFileName));
  837.         hr = HRESULT_FROM_WIN32(GetLastError());
  838.         goto ReturnHR;
  839.     }
  840.  
  841.     hrscReg = FindResource((HMODULE)hInstResDll, szID, szType);
  842.  
  843.     if (NULL == hrscReg)
  844.     {
  845.         ATLTRACE(_T("Failed to FindResource on ID:%s TYPE:%s\n"), szID, szType);
  846.         hr = HRESULT_FROM_WIN32(GetLastError());
  847.         goto ReturnHR;
  848.     }
  849.  
  850.     hReg = LoadResource((HMODULE)hInstResDll, hrscReg);
  851.  
  852.     if (NULL == hReg)
  853.     {
  854.         ATLTRACE(_T("Failed to LoadResource \n"));
  855.         hr = HRESULT_FROM_WIN32(GetLastError());
  856.         goto ReturnHR;
  857.     }
  858.  
  859.     dwSize = SizeofResource((HMODULE)hInstResDll, hrscReg);
  860.     szRegA = (LPSTR)hReg;
  861.     if (szRegA[dwSize] != NULL)
  862.     {
  863.         szRegA = (LPSTR)_alloca(dwSize+1);
  864.         memcpy(szRegA, (void*)hReg, dwSize+1);
  865.         szRegA[dwSize] = NULL;
  866.     }
  867.  
  868.     szReg = A2T(szRegA);
  869.  
  870. #ifdef _DEBUG
  871.     OutputDebugString(szReg); //would call ATLTRACE but szReg is > 512 bytes
  872.     OutputDebugString(_T("\n"));
  873. #endif //_DEBUG
  874.  
  875.     hr = parser.RegisterBuffer(szReg, bRegister);
  876.  
  877. ReturnHR:
  878.  
  879.     if (NULL != hInstResDll)
  880.         FreeLibrary((HMODULE)hInstResDll);
  881.     return hr;
  882. }
  883.  
  884. HRESULT STDMETHODCALLTYPE CRegObject::ResourceRegister(LPCOLESTR szFileName, UINT nID, LPCOLESTR szType)
  885. {
  886.     USES_CONVERSION;
  887.     return RegisterFromResource(szFileName, MAKEINTRESOURCE(nID), OLE2CT(szType), TRUE);
  888. }
  889.  
  890. HRESULT STDMETHODCALLTYPE CRegObject::ResourceRegisterSz(LPCOLESTR szFileName, LPCOLESTR szID, LPCOLESTR szType)
  891. {
  892.     USES_CONVERSION;
  893.  
  894.     if (szID == NULL || szType == NULL)
  895.         return E_INVALIDARG;
  896.  
  897.     return RegisterFromResource(szFileName, OLE2CT(szID), OLE2CT(szType), TRUE);
  898. }
  899.  
  900. HRESULT STDMETHODCALLTYPE CRegObject::ResourceUnregister(LPCOLESTR szFileName, UINT nID, LPCOLESTR szType)
  901. {
  902.     USES_CONVERSION;
  903.     return RegisterFromResource(szFileName, MAKEINTRESOURCE(nID), OLE2CT(szType), FALSE);
  904. }
  905.  
  906. HRESULT STDMETHODCALLTYPE CRegObject::ResourceUnregisterSz(LPCOLESTR szFileName, LPCOLESTR szID, LPCOLESTR szType)
  907. {
  908.     USES_CONVERSION;
  909.     if (szID == NULL || szType == NULL)
  910.         return E_INVALIDARG;
  911.  
  912.     return RegisterFromResource(szFileName, OLE2CT(szID), OLE2CT(szType), FALSE);
  913. }
  914.  
  915. HRESULT CRegObject::RegisterWithString(LPCOLESTR bstrData, BOOL bRegister)
  916. {
  917.     USES_CONVERSION;
  918.     CRegParser  parser(this);
  919.  
  920.  
  921.     LPCTSTR szReg = OLE2CT(bstrData);
  922.  
  923. #ifdef _DEBUG
  924.     OutputDebugString(szReg); //would call ATLTRACE but szReg is > 512 bytes
  925.     OutputDebugString(_T("\n"));
  926. #endif //_DEBUG
  927.  
  928.     HRESULT hr = parser.RegisterBuffer((LPTSTR)szReg, bRegister);
  929.  
  930.     return hr;
  931. }
  932.  
  933. HRESULT CRegObject::ClearReplacements()
  934. {
  935.     m_csMap.Lock();
  936.     HRESULT hr = m_RepMap.ClearReplacements();
  937.     m_csMap.Unlock();
  938.     return hr;
  939. }
  940.  
  941.  
  942. LPCOLESTR CRegObject::StrFromMap(LPTSTR lpszKey)
  943. {
  944.     m_csMap.Lock();
  945.     LPCOLESTR lpsz = m_RepMap.Find(lpszKey);
  946.     if (lpsz == NULL) // not found!!
  947.         ATLTRACE(_T("Map Entry not found\n"));
  948.     m_csMap.Unlock();
  949.     return lpsz;
  950. }
  951.  
  952. HRESULT CRegObject::MemMapAndRegister(LPCOLESTR bstrFileName, BOOL bRegister)
  953. {
  954.     USES_CONVERSION;
  955.  
  956.     CRegParser  parser(this);
  957.  
  958.     HANDLE hFile = CreateFile(OLE2CT(bstrFileName), GENERIC_READ, 0, NULL,
  959.                               OPEN_EXISTING,
  960.                               FILE_ATTRIBUTE_READONLY,
  961.                               NULL);
  962.  
  963.     if (NULL == hFile)
  964.     {
  965.         ATLTRACE(_T("Failed to CreateFile on %s\n"), OLE2CT(bstrFileName));
  966.         return HRESULT_FROM_WIN32(GetLastError());
  967.     }
  968.  
  969.     DWORD cbFile = GetFileSize(hFile, NULL); // No HiOrder DWORD required
  970.  
  971.     HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  972.  
  973.     if (NULL == hMapping)
  974.     {
  975.         ATLTRACE(_T("Failed to CreateFileMapping\n"));
  976.         return HRESULT_FROM_WIN32(GetLastError());
  977.     }
  978.  
  979.     LPVOID pMap = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
  980.  
  981.     if (NULL == pMap)
  982.     {
  983.         ATLTRACE(_T("Failed to MapViewOfFile\n"));
  984.         return HRESULT_FROM_WIN32(GetLastError());
  985.     }
  986.  
  987.     LPTSTR szReg = A2T((char*)pMap);
  988.  
  989.     if (chEOS != szReg[cbFile]) //ensure buffer is NULL terminated
  990.     {
  991.         ATLTRACE(_T("ERROR : Bad or missing End of File\n"));
  992.         return E_FAIL; // make a real error
  993.     }
  994.  
  995. #ifdef _DEBUG
  996.     OutputDebugString(szReg); //would call ATLTRACE but szReg is > 512 bytes
  997.     OutputDebugString(_T("\n"));
  998. #endif //_DEBUG
  999.  
  1000.     HRESULT hRes = parser.RegisterBuffer(szReg, bRegister);
  1001.  
  1002. //  if (FAILED(hRes))
  1003. //      re = parser.GetRegException();
  1004.  
  1005.     UnmapViewOfFile(pMap);
  1006.     CloseHandle(hMapping);
  1007.     CloseHandle(hFile);
  1008.  
  1009.     return hRes;
  1010. }
  1011.  
  1012. HRESULT STDMETHODCALLTYPE CRegObject::FileRegister(LPCOLESTR bstrFileName)
  1013. {
  1014.     return MemMapAndRegister(bstrFileName, TRUE);
  1015. }
  1016.  
  1017. HRESULT STDMETHODCALLTYPE CRegObject::FileUnregister(LPCOLESTR bstrFileName)
  1018. {
  1019.     return MemMapAndRegister(bstrFileName, FALSE);
  1020. }
  1021.  
  1022. HRESULT STDMETHODCALLTYPE CRegObject::StringRegister(LPCOLESTR bstrData)
  1023. {
  1024.     return RegisterWithString(bstrData, TRUE);
  1025. }
  1026.  
  1027. HRESULT STDMETHODCALLTYPE CRegObject::StringUnregister(LPCOLESTR bstrData)
  1028. {
  1029.     return RegisterWithString(bstrData, FALSE);
  1030. }
  1031.  
  1032. #ifndef ATL_NO_NAMESPACE
  1033. }; //namespace ATL
  1034. #endif
  1035.